/**
 * Copyright 2013 Green global company. All rights reserved. Use is subject to license terms.
 */
package webdev.imgloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.joda.time.DateTime;

import webdev.utils.ImageHelperUtil;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Environment;
import android.util.Log;
import android.widget.ImageView;
import dev.danang.R;

public class ImageLoaderLocal {

	/*public static final int TYPE_NORMAL = 0;
	public static final int TYPE_CIRCLE = 1;
	public static final int TYPE_ROUND_4_CORNER = 2;
	public static final int TYPE_ROUND_2_CORNER = 3;*/
    
    MemoryCache memoryCache = new MemoryCache();
    FileCache fileCache;
    private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
    ExecutorService executorService;
    boolean mPauseWork = false;
    private final Object mPauseWorkLock = new Object();
    protected Resources mResources;
    private static final int FADE_IN_TIME = 200;
    private static final boolean FADE_IN_BITMAP = true;
    
    public ImageLoaderLocal(Context context) {
        fileCache = new FileCache(context);
        executorService = Executors.newFixedThreadPool(5);
        mResources = context.getResources();
    }
    
    /**
     * This method is used to load image
     * @param url is the url to load image
     * @param imageView is the image view that you need to load image on
     * @param hasImageSmall is true if there is a small bitmap on image view before
     *        hasImageSmall is false if there is no a small bitmap on image view before
     * @param requestWidth is with of image view
     * @param requestHeight is height of image view
     * @param typeImage is the type of image that you want to load. There are four types
     *        TYPE_NORMAL load image normal
     *        TYPE_CIRCLE load image circle
     *        TYPE_ROUND_4_CORNER load image with round four corners
     *        TYPE_ROUND_2_CORNER load image with round two corners at bottom
     */
    public void DisplayImage(String path, ImageView imageView, int requestWidth, int requestHeight) {
        imageViews.put(imageView, path);
        Bitmap bitmap = memoryCache.get(path);
        if (bitmap != null) {
        	imageView.setImageBitmap(bitmap);
        	/*switch (typeImage) {
			case TYPE_NORMAL:
				imageView.setImageBitmap(bitmap);
				break;
			case TYPE_CIRCLE:
				imageView.setImageBitmap(ImageHelperUtil.getCircleBitmap(bitmap));
				break;
			case TYPE_ROUND_4_CORNER:
				imageView.setImageBitmap(ImageHelperUtil.getRound4CornerBitmap(bitmap));
				break;
			case TYPE_ROUND_2_CORNER:
				imageView.setImageBitmap(ImageHelperUtil.getRound2BottomCornerBitmap(bitmap));
				break;
			default:
				break;
			}*/
        } else {
            queuePhoto(path, imageView, requestWidth, requestHeight);
            // If has image small, don't set image default
           /* if (hasImageSmall == false) {
            	imageView.setImageResource(R.color.color_white);
            }*/
            /*if (typeImage == TYPE_CIRCLE) {
            	imageView.setImageResource(R.drawable.friends_circle_no_avatar);
            } else {
            	if (hasImageSmall == false) {
                	imageView.setImageResource(R.color.color_white);
                }
            }*/
        }
    }

    private void queuePhoto(String path, ImageView imageView, int requestWidth, int requestHeight) {
        PhotoToLoad p = new PhotoToLoad(path, imageView);
        executorService.submit(new PhotosLoader(p, requestWidth, requestHeight));
    }
    
    @SuppressWarnings("null")
	public Bitmap getBitmap(String path, int requestWidth, int requestHeight) {
        File f = fileCache.getFile(path);
        
        // from SD cache
        Bitmap b = decodeFile(f, requestWidth, requestHeight);
        if (b != null)
            return b;
        
        // from web
        try {
        	String extStorageDirectory = Environment.getExternalStorageDirectory()
    				.toString();
        	Bitmap bitmap = null;
    		Log.i("ImageUtil", "extStorageDirectory: " + extStorageDirectory);
    		OutputStream outStream = null;
    		DateTime dt = DateTime.now();
    		String filename = dt.toString();
    		File file = new File(extStorageDirectory, filename + "." + "PNG");
    		try {
    			outStream = new FileOutputStream(file);
    			bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    			
    			try {
    				outStream.flush();
    				outStream.close();
    			bitmap = decodeFile(f, requestWidth, requestHeight);	
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			 return bitmap;
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
            return bitmap;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    //decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f, int requestWidth, int requestHeight) {
        try {
            //decode image size
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f), null, options);
            
            options.inSampleSize = ImageHelperUtil.calculateInSampleSize(options, requestWidth, requestHeight);
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, options);
        } catch (FileNotFoundException e) {}
        return null;
    }

    // Task for the queue
    private class PhotoToLoad {
        public String Path;
        public ImageView imageView;
        /**
         * Constructor
         * @param u: string url
         * @param i: imageView
         */
        public PhotoToLoad(String path, ImageView i) {
        	Path = path; 
            imageView = i;
        }
    }
    
    class PhotosLoader implements Runnable {
        PhotoToLoad photoToLoad;
        int requestWidth;
        int requestHeight;
        
        /**
         * Constructor
         * @param photoToLoad
         */
        PhotosLoader(PhotoToLoad photoToLoad, int requestWidth, int requestHeight) {
            this.photoToLoad = photoToLoad;
            this.requestWidth = requestWidth;
            this.requestHeight = requestHeight;
        }
        
        @Override
        public void run() {
        	// Wait here if work is paused and the task is not cancelled
            synchronized (mPauseWorkLock) {
                while (mPauseWork) {
                    try {
                        mPauseWorkLock.wait();
                    } catch (InterruptedException e) {}
                }
            }
        	
            if (imageViewReused(photoToLoad)) {
                return;
            }
            Bitmap bmp = getBitmap(photoToLoad.Path, this.requestWidth, this.requestHeight);
            memoryCache.put(photoToLoad.Path, bmp);
            if (imageViewReused(photoToLoad)) {
                return;
            }
            BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
            Activity a =(Activity)photoToLoad.imageView.getContext();
            a.runOnUiThread(bd);
        }
    }
    
    /**
     * @param photoToLoad
     * @return true if the photoToLoad == null
     * @return false if the photoToLoad already existed
     */
    boolean imageViewReused(PhotoToLoad photoToLoad) {
        String tag = imageViews.get(photoToLoad.imageView);
        if( tag == null || !tag.equals(photoToLoad.Path) )
            return true;
        return false;
    }
    
    // Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable {
        Bitmap bitmap;
        PhotoToLoad photoToLoad;
        
        /**
         * Constructor
         * @param b
         * @param p
         */
        public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
        	bitmap = b;
        	photoToLoad = p;
        }
        
        public void run() {
            if (imageViewReused(photoToLoad))
                return;
            if (bitmap != null) {
            	/*switch (typeImage) {
    			case TYPE_NORMAL:
    				break;
    			case TYPE_CIRCLE:
    				bitmap = ImageHelperUtil.getCircleBitmap(bitmap);
    				break;
    			case TYPE_ROUND_4_CORNER:
    				bitmap = ImageHelperUtil.getRound4CornerBitmap(bitmap);
    				break;
    			case TYPE_ROUND_2_CORNER:
    				bitmap = ImageHelperUtil.getRound2BottomCornerBitmap(bitmap);
    				break;
    			default:
    				break;
    			}*/

            	if (FADE_IN_BITMAP) {
            		final TransitionDrawable td =
                            new TransitionDrawable(new Drawable[] {
                                    new ColorDrawable(android.R.color.transparent),
                                    new BitmapDrawable(mResources, bitmap)
                            });
                    photoToLoad.imageView.setImageDrawable(td);
                    td.startTransition(FADE_IN_TIME);
            	}  else {
            		photoToLoad.imageView.setImageBitmap(bitmap);
            	} // end if
            } else {
                photoToLoad.imageView.setImageResource(R.drawable.no_image);
            } // end if
        }
    }
    
    public void clearCache() {
        memoryCache.clear();
        fileCache.clear();
    }

    public void setPauseWork(boolean pauseWork) {
    	synchronized (mPauseWorkLock) {
            mPauseWork = pauseWork;
            if (!mPauseWork) {
                mPauseWorkLock.notifyAll();
            }
        }
    }
}
